import express from "express";
import bodyParser from "body-parser";
import dotenv from "dotenv";
import { CozeAPI, ChatEventType } from '@coze/api';
dotenv.config();

const app = express();
app.use(bodyParser.json());
const coze_api_base = process.env.COZE_API_BASE || "api.coze.com";
const default_bot_id = process.env.BOT_ID || "";
const botConfig = process.env.BOT_CONFIG ? JSON.parse(process.env.BOT_CONFIG) : {};
var corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers":
    "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization",
  "Access-Control-Max-Age": "86400",
};

app.use((req, res, next) => {
  res.set(corsHeaders);
  if (req.method === 'OPTIONS') {
    return res.status(204).end();
  }
  console.log('Request Method:', req.method); 
  console.log('Request Path:', req.path);
  next();
});
app.get("/", (req, res) => {
  res.send(`
    <html>
      <head>
        <title>COZE2OPENAI</title>
      </head>
      <body>
        <h1>Coze2OpenAI</h1>
        <p>Congratulations! Your project has been successfully deployed.</p>
      </body>
    </html>
  `);
});

app.post("/v1/chat/completions", async (req, res) => {
  const authHeader =
    req.headers["authorization"] || req.headers["Authorization"];
  if (!authHeader) {
    return res.status(401).json({
      code: 401,
      errmsg: "Unauthorized.",
    });
  } else {
    const token = authHeader.split(" ")[1];
    if (!token) {
      return res.status(401).json({
        code: 401,
        errmsg: "Unauthorized.",
      });
    }
  }
  try {
    const data = req.body;
    const messages = data.messages;
    const model = data.model;
    const user = data.user !== undefined ? data.user : "apiuser";
    const additionalMessages = [];
    for (let i = 0; i < messages.length; i++) {
      const message = messages[i];
      const role = message.role;
      const content = message.content;
      
      additionalMessages.push({
        role: role,
        content: content,
        content_type: "text"
      });
    }

    const stream = data.stream !== undefined ? data.stream : false;
    const bot_id = model && botConfig[model] ? botConfig[model] : default_bot_id;
    const requestBody = {
      bot_id: bot_id,
      user_id: user,
      additional_messages: additionalMessages,
      stream: true,
      auto_save_history: false,
    };
    const coze_client = new CozeAPI({baseURL:`https://${coze_api_base}`,token:authHeader.split(" ")[1],debug:false});
    const v = coze_client.chat.stream(requestBody);
    if (stream) {
      for await (const part of v) {
        const dtNow = Date.now();
        const chunkId = `chatcmpl-${dtNow}`;
        const chunkCreated = Math.floor(dtNow / 1000);
        if (part.event === ChatEventType.CONVERSATION_MESSAGE_COMPLETED) {
          const { role, type, content, content_type } = part.data;
          if (role === 'assistant' && type === 'answer' && content_type === "text") {
            res.write(
              "data: " +
                JSON.stringify({
                  id: chunkId,
                  object: "chat.completion.chunk",
                  created: chunkCreated,
                  model: model,
                  choices: [
                    {
                      index: 0,
                      delta: {
                        content: content,
                      },
                      finish_reason: null,
                    },
                  ],
                }) +
                "\n\n"
            );
          }
        } else if (part.event === ChatEventType.DONE) {
          res.write(
            "data: " +
              JSON.stringify({
                id: chunkId,
                object: "chat.completion.chunk",
                created: chunkCreated,
                model: model,
                choices: [
                  {
                    index: 0,
                    delta: {},
                    finish_reason: "stop",
                  },
                ],
              }) +
              "\n\n"
          );
          res.write("data: [DONE]\n\n");
          res.end();
        } else if (part.event === ChatEventType.ERROR) {
          const { code, msg } = part.data;
          const errorMsg = code + " " + msg;
          res.write(
            `data: ${JSON.stringify({ error: {
                error: "Unexpected response from Coze API.",
                message: errorMsg
              }
            })}\n\n`
          );
          res.write("data: [DONE]\n\n");
          res.end();
        }
      }
    } else {
      const stringBuilder = [];
      for await (const part of v) {
        if (part.event === ChatEventType.CONVERSATION_MESSAGE_COMPLETED) {
          const { role, type, content, content_type } = part.data;
          if (role === 'assistant' && type === 'answer' && content_type === "text") {
            stringBuilder.push(content);
          }
        } else if (part.event === ChatEventType.ERROR) {
          const { code, msg } = part.data;
          res
            .status(500)
            .json({ error: {
                error: "Unexpected response from Coze API.",
                message: code + " " + msg
              }
            });
          break;
        }
      }
      if (stringBuilder.length > 0) {
        const dtNow = Date.now();
        const chunkId = `chatcmpl-${dtNow}`;
        const chunkCreated = Math.floor(dtNow / 1000);
        const formattedResponse = {
          id: chunkId,
          object: "chat.completion",
          created: chunkCreated,
          model: model,
          choices: [
            {
              index: 0,
              message: {
                role: "assistant",
                content: stringBuilder.join(''),
              },
              finish_reason: "stop",
            },
          ],
        };
        const jsonResponse = JSON.stringify(formattedResponse, null, 2);
        res.set("Content-Type", "application/json");
        res.send(jsonResponse);
      } else {
        res.status(500).json({ error: "No answer message found." });
      }
    }
  } catch (error) {
    console.error("Error:", error);
  }
});

const server = app.listen(process.env.PORT || 3000, function () {
  let port = server.address().port
  console.log('Ready! Listening all IP, port: %s. Example: at http://localhost:%s', port, port)
});
